package com.itcs.box.server.service.impl;

import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

import com.alibaba.fastjson.JSON;
import com.itcs.box.BoxConstants;
import com.itcs.box.domain.BoxRequest;
import com.itcs.box.server.resolver.MsgResolverAdapter;
import com.itcs.box.server.server.NettyChannelMap;
import com.itcs.box.server.service.NettyMsgResolveService;
import com.itcs.dubbo.service.DubboService;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;

/**
 * netty消息解析
 * 
 * @author LiuPeng
 * @date 2017年12月12日
 * 
 */
@Component
public class NettyMsgResolveServiceImpl implements NettyMsgResolveService, ApplicationContextAware {

	private Log logger = LogFactory.getLog(getClass());

	private List<MsgResolverAdapter> resolverAdapters;

	@Resource(name = "itcsApp")
	private DubboService itcsApp;

	@Override
	public void resolve(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf) {
		String paramJson = getDecode(byteBuf);
		try {
			BoxRequest boxRequest = JSON.parseObject(paramJson, BoxRequest.class);

			if (!"1001".equals(boxRequest.getMessgeType())) {
				// 验证通讯盒登录状态
				if (!validateChannel(boxRequest, channelHandlerContext)) {
					return;
				}
			}

			for (MsgResolverAdapter resolverAdapter : resolverAdapters) {
				if (resolverAdapter.support(boxRequest)) {
					resolverAdapter.resolve(channelHandlerContext, boxRequest);
					return;
				}
			}
			logger.warn("收到通讯盒消息,但未找到解析类," + JSON.toJSONString(paramJson));
		} catch (Exception e) {
			logger.error("解析通讯盒消息失败" + e.getMessage() + "-ParamJSON:" + paramJson, e);
		}

	}

	@Override
	public void channelInactive(ChannelHandlerContext ctx, String deviceId, String channelId) {
		Map<String, Object> reqRecord = new HashMap<>();
		reqRecord.put("deviceId", deviceId);
		reqRecord.put("channelId", channelId);
		try {
			itcsApp.exchange("boxChannelInactive", reqRecord);
		} catch (Exception e) {
			logger.error("通讯盒下线调用AppServer失败", e);
		}
	}

	/**
	 * 验证通讯盒登录状态
	 * 
	 * @param boxRequest
	 * @return
	 */
	private boolean validateChannel(BoxRequest boxRequest, ChannelHandlerContext channelHandlerContext) {
		try {
			String deviceId = boxRequest.getData().getDeviceId();
			ChannelHandlerContext channel = NettyChannelMap.get(deviceId);
			if (channel == null) {
				logger.warn("通讯盒[" + deviceId + "],未登录不允许访问服务。");
			} else if (channelHandlerContext != channel) {
				String thisDeviceId = NettyChannelMap.getKeyByValue(channelHandlerContext);
				logger.warn("通讯盒[" + thisDeviceId + "],发送其他通讯盒数据:" + deviceId);
			} else {
				return true;
			}
		} catch (Exception e) {
			logger.error("校验通讯盒消息失败" + e.getMessage() + "-ParamJSON:" + JSON.toJSONString(boxRequest), e);
		}
		return false;
	}

	public String getDecode(ByteBuf byteBuf) {
		String jsonString = byteBuf.toString(BoxConstants.CHARSET_UTF8).trim();
		// 测试工具编码为gb2312 如果是测试工具将进行转码
		if (jsonString.contains("�")) {
			jsonString = byteBuf.toString(Charset.forName("gb2312")).trim();
		}
		return jsonString;
	}

	@Override
	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
		initResolverAdapters(applicationContext);
	}

	/**
	 * 初始化resolverAdapters
	 * 
	 * @param applicationContext
	 */
	private void initResolverAdapters(ApplicationContext applicationContext) {
		if (resolverAdapters == null) {
			Map<String, MsgResolverAdapter> beanMap = BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext,
					MsgResolverAdapter.class, true, false);
			resolverAdapters = new ArrayList<>(beanMap.size());
			for (Map.Entry<String, MsgResolverAdapter> entry : beanMap.entrySet()) {
				resolverAdapters.add(entry.getValue());
			}
			logger.info("初始化netty解析适配器完成:" + resolverAdapters.size());
		}
	}

}
